//
// Created by admin on 2022/9/13.
//

#include "TimerWheel.h"


/**
 * CORE step 最小间隔ms existTime 最长持续时间ms
 * */
int TimerWheelUtil::TimerWheel::initTimerWheel(int step, long existTime) {
    if (MS_UNIT % step != 0) {
        std::cout << "minus step is not divide by " << MS_UNIT << std::endl;
        return -1;
    }
    if (existTime < step) {
        std::cout << "existTime must be bigger than step value!" << MS_UNIT << std::endl;
        return -1;
    }
//    初始化timer结构
    long tmpExistTime = existTime;
    stepMs_ = step;
    timePos_ = TimePos{0, 0, 0, 0, stepMs_};
    msGradeCount_ = MS_UNIT / stepMs_;
    ssGradeCount_ = std::min((long) SECOND_UNIT, tmpExistTime /= MS_UNIT);
    minGradeCount_ = std::min((long) MIN_UNIT, tmpExistTime /= SECOND_UNIT);
    hourGradeCount_ = std::min((long) HOUR_UNIT, tmpExistTime /= MIN_UNIT);

    eventCallBackList = new std::list<EventInfo>[msGradeCount_ + ssGradeCount_ + minGradeCount_ + hourGradeCount_];
//    启动伴随线程，负责轮询
    std::thread thread([&] {
        this->DoLoop();
    });
    thread.detach();
    return 1;
}


int TimerWheelUtil::TimerWheel::deleteTimer(int timerId) {
    std::lock_guard<std::mutex> ol{mutex_};
    assert(timerMap.find(timerId) != timerMap.end());
    auto &eventMap = timerMap[timerId];
    eventMap.first->erase(eventMap.second);
    timerMap.erase(timerId);
    --cnt;
    return 1;
}

void TimerWheelUtil::TimerWheel::DoLoop() {
    while (true) {
        std::this_thread::sleep_until(std::chrono::steady_clock::now() + std::chrono::milliseconds(stepMs_));
        TimePos tp{timePos_.Add(stepMs_)};
        do {
            std::lock_guard<std::mutex> ol{mutex_};
            if (isOk) {
                DealTimeWheeling(eventCallBackList[tp.absPos()]);
            }
        } while (!tp.BeHandle() && (tp.Degrade(), true));
    }
}

void TimerWheelUtil::TimerWheel::DealTimeWheeling(std::list<EventInfo> &leinfo) {
    StaticDealTimeWheeling(this, leinfo);
}

int TimerWheelUtil::TimerWheel::InsertTimer(const TimerWheel::EventInfo &einfo) {
    auto &evlist = eventCallBackList[einfo.timePos->absPos()];
    evlist.push_back(einfo);
    timerMap[einfo.timeId] = {&evlist, std::prev(evlist.end())};
    return 1;
}



